#include <iostream>
#include "OrthoCamera.h"

#define RAY_AMMOUNT 5			// Debug!

COrthoCamera::COrthoCamera(void)
{
}

COrthoCamera::COrthoCamera(CVector _pos, CVector _tgt):CCamera(_pos, _tgt)
{
}

COrthoCamera::COrthoCamera(CVector _pos, CVector _tgt, CVector _up, float _np, float _fp, float _fov):CCamera(_pos, _tgt, _up, _np, _fp, _fov)
{
}

COrthoCamera::~COrthoCamera(void)
{
	delete m_Position;
	delete m_Target;
	delete m_Up;
	delete m_ViewPlane;
}

void COrthoCamera::Render()
{
	//RenderInstruction2();
	//Test();
}

CLightIntensity *COrthoCamera::AntyAliasing(int _x, int _y)
{
	// Antyaliasing (regular) 5x5 grid on pixel
	float actualQuadCenterX = -1.0f;
	float actualQuadCenterY = -1.0f;
	int interResult = -1;
	CRay *ray = NULL;
	CLightIntensity *bgColor = new CLightIntensity();
	CLightIntensity *sphColor = new CLightIntensity(1.0f, 0.4f, 0.0f);
	CSphere *sphere = new CSphere(CVector(0.0f, 0.0f, 0.0f), 0.4f);
	float r = 0.0f;
	float g = 0.0f;
	float b = 0.0f;
	float dX = m_PixelWidth / (float) RAY_AMMOUNT;
	float dY = m_PixelHeight / (float) RAY_AMMOUNT;

	for (int i = 0; i < RAY_AMMOUNT; i++)
	{
		for (int j = 0; j < RAY_AMMOUNT; j++)
		{
			actualQuadCenterX = (-0.5f + _x * m_PixelWidth) + (dX / 2.0f + i * dX);
			actualQuadCenterY = (-0.5f + _y * m_PixelHeight) + (dY / 2.0f + j * dY);
			
			ray = new CRay(CVector(actualQuadCenterX, actualQuadCenterY, -10.0f), CVector(0.0f, 0.0f, 1.0f));
//			interResult = sphere->Intersect(*ray, CVector(), CVector());

			if (interResult > 0)
			{
				r += sphColor->GetRed();
				g += sphColor->GetGreen();
				b += sphColor->GetBlue();
			}
			else
			{
				r += bgColor->GetRed();
				g += bgColor->GetGreen();
				b += bgColor->GetBlue();				
			}

			delete ray;
		}
	}

	r /= (float) (RAY_AMMOUNT * RAY_AMMOUNT);
	g /= (float) (RAY_AMMOUNT * RAY_AMMOUNT);
	b /= (float) (RAY_AMMOUNT * RAY_AMMOUNT);

	return new CLightIntensity(r, g, b);
}

CLightIntensity *COrthoCamera::AntyAliasing(int _x, int _y, int _depth)
{
	// Antyaliasing (regular) 5x5 grid on pixel
	float actualQuadCenterX = -1.0f;
	float actualQuadCenterY = -1.0f;
	int interResult = -1;
	CRay *ray = NULL;
	CLightIntensity *bgColor = new CLightIntensity();
	CLightIntensity *sphColor = new CLightIntensity(1.0f, 0.4f, 0.0f);
	CSphere *sphere = new CSphere(CVector(0.0f, 0.0f, 0.0f), 0.4f);
	float r = 0.0f;
	float g = 0.0f;
	float b = 0.0f;
	float dX = m_PixelWidth / (float) _depth;
	float dY = m_PixelHeight / (float) _depth;

	for (int i = 0; i < _depth; i++)
	{
		for (int j = 0; j < _depth; j++)
		{

			actualQuadCenterX = (-0.5f + _x * m_PixelWidth) + (dX / 2.0f + i * dX);
			actualQuadCenterY = (-0.5f + _y * m_PixelHeight) + (dY / 2.0f + j * dY);
			
			ray = new CRay(CVector(actualQuadCenterX, actualQuadCenterY, -10.0f), CVector(0.0f, 0.0f, 1.0f));
//			interResult = sphere->Intersect(*ray, CVector(), CVector());

			if (interResult > 0)
			{
				r += sphColor->GetRed();
				g += sphColor->GetGreen();
				b += sphColor->GetBlue();
			}
			else
			{
				r += bgColor->GetRed();
				g += bgColor->GetGreen();
				b += bgColor->GetBlue();				
			}

			delete ray;
		}
	}

	r /= (float) (_depth * _depth);
	g /= (float) (_depth * _depth);
	b /= (float) (_depth * _depth);

	return new CLightIntensity(r, g, b);
}

// ---------------------------------- PART CLIGHTINTENSITY!!!
CLightIntensity MinColor(CLightIntensity& _colA, CLightIntensity& _colB)
{
	return CLightIntensity(
				std::min(_colA.GetRed(), _colB.GetRed()),
				std::min(_colA.GetGreen(), _colB.GetGreen()),
				std::min(_colA.GetBlue(), _colB.GetBlue())
				);
}

CLightIntensity MaxColor(CLightIntensity& _colA, CLightIntensity& _colB)
{
	return CLightIntensity(
				std::max(_colA.GetRed(), _colB.GetRed()),
				std::max(_colA.GetGreen(), _colB.GetGreen()),
				std::max(_colA.GetBlue(), _colB.GetBlue())
				);
}

CLightIntensity MedColor(CLightIntensity **_colors, int _w, int _h)
{
	float r = 0.0f;
	float g = 0.0f;
	float b = 0.0f;

	for (int i = 0; i < _w; i++)
		for (int j = 0; j < _h; j++)
		{
			r += _colors[i][j].GetRed();
			g += _colors[i][j].GetGreen();
			b += _colors[i][j].GetBlue();
		}

	r /= (_w * _h);
	g /= (_w * _h);
	b /= (_w * _h);

	return CLightIntensity(r, g, b);
}

// ---------------------------------- PART CLIGHTINTENSITY!!!

bool COrthoCamera::AntyAliasingDepth(int _x, int _y, float _diff, int _depth, CLightIntensity& _destColor)
{
	// Antyaliasing (regular) 5x5 grid on pixel
	float actualQuadCenterX = -1.0f;
	float actualQuadCenterY = -1.0f;
	int interResult = -1;
	CRay *ray = NULL;
	CLightIntensity *bgColor = new CLightIntensity();
	CLightIntensity *sphColor = new CLightIntensity(1.0f, 0.4f, 0.0f);
	CSphere *sphere = new CSphere(CVector(0.0f, 0.0f, 0.0f), 0.4f);
	float r = 0.0f;
	float g = 0.0f;
	float b = 0.0f;
	float dX = m_PixelWidth / (float) _depth;
	float dY = m_PixelHeight / (float) _depth;
	CLightIntensity **colors = new CLightIntensity*[_depth];
	CLightIntensity minColor = CLightIntensity(1.0f, 1.0f, 1.0f);
	CLightIntensity maxColor = CLightIntensity(0.0f, 0.0f, 0.0f);

	for (int i = 0; i < _depth; i++)
	{
		colors[i] = new CLightIntensity[_depth];

		for (int j = 0; j < _depth; j++)
		{
			actualQuadCenterX = (-0.5f + _x * m_PixelWidth) + (dX / 2.0f + i * dX);
			actualQuadCenterY = (-0.5f + _y * m_PixelHeight) + (dY / 2.0f + j * dY);

			
			ray = new CRay(CVector(actualQuadCenterX, actualQuadCenterY, -10.0f), CVector(0.0f, 0.0f, 1.0f));
//			interResult = sphere->Intersect(*ray, CVector(), CVector());

			if (interResult > 0)
			{
				colors[i][j] = CLightIntensity();
				colors[i][j].SetRed( sphColor->GetRed() );
				colors[i][j].SetGreen( sphColor->GetGreen() );
				colors[i][j].SetBlue( sphColor->GetBlue() );
			}
			else
			{
				colors[i][j] = CLightIntensity();
				colors[i][j].SetRed( bgColor->GetRed() );
				colors[i][j].SetGreen( bgColor->GetGreen() );
				colors[i][j].SetBlue( bgColor->GetBlue() );			
			}

			delete ray;

			minColor = MinColor(colors[i][j], minColor);
			maxColor = MaxColor(colors[i][j], maxColor);
		}
	}

	_destColor = MedColor(colors, _depth, _depth);

	if ( (maxColor.GetRed() - minColor.GetRed() > _diff ) || (maxColor.GetGreen() - minColor.GetGreen() > _diff ) || (maxColor.GetBlue() - minColor.GetBlue() > _diff ) )
		return true;
		
	return false;
}

CLightIntensity *COrthoCamera::AntyAliasingAdaptive(int _x, int _y, float _diff, int _maxDepth)
{
	float actualQuadCenterX = -1.0f;
	float actualQuadCenterY = -1.0f;
	int interResult = -1;
	CRay *ray = NULL;
	CLightIntensity *bgColor = new CLightIntensity();
	CLightIntensity *sphColor = new CLightIntensity(1.0f, 0.4f, 0.0f);
	CSphere *sphere = new CSphere(CVector(0.0f, 0.0f, 0.0f), 0.4f);
	float r = 0.0f;
	float g = 0.0f;
	float b = 0.0f;
	int depth = 2;
	float dX = m_PixelWidth / (float) depth;
	float dY = m_PixelHeight / (float) depth;
	CLightIntensity *retCol = new CLightIntensity();

	while (AntyAliasingDepth(_x, _y, _diff, depth++, *retCol) && depth < _maxDepth)
	{}

	return retCol;
}

// For instruction 2:
void COrthoCamera::RenderInstruction2()
{
	float pixCenterX = -1.0f;
	float pixCenterY = -1.0f;
	int interResult = -1;
	CRay *ray = NULL;
	CLightIntensity *bgColor = new CLightIntensity();
	CLightIntensity *sphColor = new CLightIntensity(1.0f, 0.4f, 0.0f);

	CSphere *sphere = new CSphere(CVector(0.0f, 0.0f, 0.0f), 0.4f);

	for (int i = 0; i < m_ViewPlane->GetWidth(); i++)
	{
		//std::cout << "\n";

		for (int j = 0; j < m_ViewPlane->GetHeight(); j++)
		{
			pixCenterX = -0.5f + (i + 0.5f) * m_PixelWidth;
			pixCenterY = -0.5f + (j + 0.5f) * m_PixelHeight;
			ray = new CRay(CVector(pixCenterX, pixCenterY, -10.0f), CVector(0.0f, 0.0f, 1.0f));
//			interResult = sphere->Intersect(*ray, CVector(), CVector());

			if (interResult > 0)
			{
				m_ViewPlane->SetPixel(i, j, *sphColor);
			}
			else
			{
				m_ViewPlane->SetPixel(i, j, *bgColor);
			}

			delete ray;
		}
	}

	MASGK::CTgaBuffer *buf = new MASGK::CTgaBuffer(m_ViewPlane->GetWidth(), m_ViewPlane->GetHeight());
	buf->Save (m_ViewPlane->GetWidth(), m_ViewPlane->GetHeight(), *m_ViewPlane, "FGK_2_O.tga");
	delete buf;

	std::cout << std::endl << "RENDERING DONE...";

	// Antyaliasing
	for (int i = 0; i < m_ViewPlane->GetWidth(); i++)
	{
		for (int j = 0; j < m_ViewPlane->GetHeight(); j++)
		{
			m_ViewPlane->SetPixel(i, j, *AntyAliasing(i, j, 5));
		}
	}

	buf = new MASGK::CTgaBuffer(m_ViewPlane->GetWidth(), m_ViewPlane->GetHeight());
	buf->Save (m_ViewPlane->GetWidth(), m_ViewPlane->GetHeight(), *m_ViewPlane, "FGK_2_O_AA.tga");
	delete buf;

	std::cout << std::endl << "RENDERING WITH REGULAR ANTYALIASING DONE...";

	// Antyaliasing Adaptive (Own version)
	for (int i = 0; i < m_ViewPlane->GetWidth(); i++)
	{
		for (int j = 0; j < m_ViewPlane->GetHeight(); j++)
		{
			m_ViewPlane->SetPixel(i, j, *AntyAliasingAdaptive(i, j, 0.0000001f, 20));
		}
	}

	buf = new MASGK::CTgaBuffer(m_ViewPlane->GetWidth(), m_ViewPlane->GetHeight());
	buf->Save (m_ViewPlane->GetWidth(), m_ViewPlane->GetHeight(), *m_ViewPlane, "FGK_2_O_AAA.tga");
	delete buf;

	std::cout << std::endl << "RENDERING WITH ADAPTIVE ANTYALIASING DONE...";
}

void COrthoCamera::Test()
{
	CRay *ray;
	int interResult;
	float pixCenterX = -1.0f;
	float pixCenterY = -1.0f;

	CTriangle *triangle = new CTriangle(  
							CVector(-1.0f, 0.9f, 0.0f),
							CVector(-0.9f, 0.9f, 0.0f),
							CVector(-0.95f, 1.0f, 0.0f),
							CLightIntensity(1.0f, 0.0f, 0.0f)
							);

	CTriangle *triangle2 = new CTriangle(  
							CVector(0.9f, 0.9f, 0.0f),
							CVector(1.0f, 0.9f, 0.0f),
							CVector(0.95f, 1.0f, 0.0f),
							CLightIntensity(0.0f, 1.0f, 0.0f)
							);

	CTriangle *triangle3 = new CTriangle(  
							CVector(0.9f, -1.0f, 0.0f),
							CVector(1.0f, -1.0f, 0.0f),
							CVector(0.95f, -0.9f, 0.0f),
							CLightIntensity(0.0f, 0.0f, 1.0f)
							);

	CTriangle *triangle4 = new CTriangle(  
							CVector(-1.0f, -1.0f, 0.0f),
							CVector(-0.9f, -1.0f, 0.0f),
							CVector(-0.95f, -0.9f, 0.0f),
							CLightIntensity(1.0f, 1.0f, 0.0f)
							);

	CTriangle *triangle5 = new CTriangle(  
							CVector(-0.05f, 0.0f, 0.0f),
							CVector(0.05f, 0.0f, 0.0f),
							CVector(0.0f, 0.1f, 0.0f),
							CLightIntensity(1.0f, 1.0f, 1.0f)
							);

	for (int i = 0; i < m_ViewPlane->GetWidth(); i++)
	{
		for (int j = 0; j < m_ViewPlane->GetHeight(); j++)
		{
			pixCenterX = -1.0f + (i + 0.5f) * m_PixelWidth * 2.0f;
			pixCenterY = -1.0f + (j + 0.5f) * m_PixelHeight * 2.0f;
			ray = new CRay(CVector(pixCenterX, pixCenterY, -10.0f), CVector(0.0f, 0.0f, 1.0f));
			
//			interResult = triangle->Intersect(*ray, CVector(), CVector());
			interResult = -1;
			if (interResult > 0)
			{
				m_ViewPlane->SetPixel(i, j, *triangle->GetColor());
			}

//			interResult = triangle2->Intersect(*ray, CVector(), CVector());

			if (interResult > 0)
			{
				m_ViewPlane->SetPixel(i, j, *triangle2->GetColor());
			}

//			interResult = triangle3->Intersect(*ray, CVector(), CVector());

			if (interResult > 0)
			{
				m_ViewPlane->SetPixel(i, j, *triangle3->GetColor());
			}

//			interResult = triangle4->Intersect(*ray, CVector(), CVector());

			if (interResult > 0)
			{
				m_ViewPlane->SetPixel(i, j, *triangle4->GetColor());
			}

//			interResult = triangle5->Intersect(*ray, CVector(), CVector());

			if (interResult > 0)
			{
				m_ViewPlane->SetPixel(i, j, *triangle5->GetColor());
			}

			delete ray;
		}
	}

	delete triangle;

	MASGK::CTgaBuffer *buf = new MASGK::CTgaBuffer(m_ViewPlane->GetWidth(), m_ViewPlane->GetHeight());
	buf->Save (m_ViewPlane->GetWidth(), m_ViewPlane->GetHeight(), *m_ViewPlane, "TEST_O.tga");
	delete buf;
	
}